#pragma once

#include <chrono>
#include <cstddef>
#include <functional>
#include <memory>
#include <stdexcept>
#include <string>

#include "asycipc/transport.hpp"

namespace asycipc {

class PipeServer;
class SessionContext;

struct NamedPipeListenerOptions {
  std::string endpoint;
  std::size_t buffer_size = 4096;
};

struct NamedPipeConnectorOptions {
  std::string endpoint;
  std::chrono::milliseconds connect_timeout{5000};
  std::chrono::milliseconds retry_interval{50};
};

using NamedPipeHandshake =
    std::function<bool(PipeServer&, PipeHandle&, SessionContext&)>;
using NamedPipeShouldContinue = std::function<bool()>;

std::unique_ptr<PipeListener> CreateNamedPipeListener(
    const NamedPipeListenerOptions& options);

PipeHandlePtr ConnectNamedPipeEndpoint(
    const NamedPipeConnectorOptions& options);

class NamedPipeError : public std::runtime_error {
 public:
  using std::runtime_error::runtime_error;
};

void ServeNamedPipe(PipeServer& server, PipeListener& listener,
                    NamedPipeHandshake handshake,
                    std::chrono::milliseconds maintenance_interval,
                    NamedPipeShouldContinue should_continue,
                    std::size_t worker_threads = 0,
                    std::size_t read_buffer_size = 4096);

}  // namespace asycipc
